﻿//#define _CRT_SECURE_NO_WARNINGS
//#include <stdio.h>
//#include <time.h>
//#include <windows.h>
//#include <stdlib.h>

#include "common.h"

//int row = 3; // 定义棋盘的行数
//int col = 3; // 定义棋盘的列数
//int continous_num = 3; // 行或列连续标记符的个数（游戏获胜的条件）
//int continuous_tilt_num = 3; // 斜线连续标记符的个数（游戏获胜的条件）

#define ROW 3 // 定义棋盘的行数
#define COL 3 // 定义棋盘的列数
#define CONTINUOUS 3 // 行或列连续标记符的个数（游戏获胜的条件）
#define CONTINUOUS_TILT 3 // 斜线连续标记符的个数（游戏获胜的条件）

void select_num()
{ // 玩家自定义玩法的函数（不想写了，懒得改代码）
	int row, col, continous_num, continuous_tilt_num;
	printf("请输入棋盘的行数：");
	int row_ret = scanf("%d", &row);
	printf("请输入棋盘的列数：");
	int col_ret = scanf("%d", &col);
	printf("请输入连子（行/列）的个数：");
	int continou_ret = scanf("%d", &continous_num);
	printf("请输入斜线连子的个数：");
	int continuous_tilt_ret = scanf("%d", &continuous_tilt_num);
}

void sudoku_menu()
{ // 显示菜单的函数
	printf("##################\n");
	printf("### 三子棋游戏 ###\n");
	printf("### 1.开始游戏 ###\n");
	printf("### 0.退出游戏 ###\n");
	printf("##################\n");
}

void init_sudoku(char sudoku[ROW][COL])
{ // 初始化棋盘的函数
	int i, j;
	for (i = 0; i < ROW; ++i)
	{
		for (j = 0; j < COL; ++j)
		{
			sudoku[i][j] = ' '; // 初始化棋盘为空格
		}
	}
}

void print_sudoku(char sudoku[ROW][COL])
{ // 打印棋盘的函数
	int i, j;
	for (i = 0; i < ROW; ++i)
	{
		/*printf(" %c | %c | %c \n",
			sudoku[i][0], sudoku[i][1], sudoku[i][2]);
		if (i < row - 1)
			printf("---+---+---\n");*/
		for (j = 0; j < COL; ++j)
		{
			printf(" %c ", sudoku[i][j]);
			if (j < COL - 1)
				printf("|");
		}
		printf("\n");
		if (i < ROW - 1)
		{
			j = 0;
			for (j = 0; j < COL; ++j)
			{
				printf("---");
				if (j < COL - 1)
					printf("+");
			}
			printf("\n");
		}
	}
	printf("\n");
}

void clean_cache()
// 清理缓存区的函数，用于逐一读取缓冲区数据，遇到回车键停止（字符'\n'）
{
	while (getchar() != '\n')
		continue;
}

void player_move(char sudoku[ROW][COL])
{ // 玩家下棋的函数
	char flag_self = '*'; // 定义标记符
	while (1)
	{
		int row = 0, col = 0; // 定义行列下标
		printf("请输入行列号(空格隔开)：");
		int scanf_ret = scanf("%d %d", &row, &col);
		if (row < 1 || row > ROW || col < 1 || col > COL)
		{
			printf("输入错误，请重新输入！\n");
			clean_cache(); // 清理缓存区
			continue;
		}
		else if (' ' != sudoku[row - 1][col - 1])
		{
			printf("该位置已有棋子，请重新输入！\n");
			continue;
		}
		else // 输入正确
		{
			sudoku[row - 1][col - 1] = flag_self;// 存入自己的标记符
			break; // 跳出循环
		}
	}
}

// 电脑下棋的函数过于随机...优化算法待定...
void computer_move(char sudoku[ROW][COL])
{ // 电脑下棋的函数，随机在空格中存入电脑的标记符
	printf("电脑下棋：\n");
	int i, j; // 定义行列下标
	char flag_computer = '#'; // 定义标记符
	int count_null = 0; // 定义计数器

	for (i = 0; i < ROW; ++i)
	{
		for (j = 0; j < COL; ++j)
		{
			if (' ' == sudoku[i][j]) // 统计空格的个数
				++count_null;
		}
	}
	while (count_null > 0)
	{
		int row, col; // 定义行列下标
		row = rand() % ROW; // 随机生成行下标(0 ~ ROW-1)
		col = rand() % COL; // 随机生成列下标(0 ~ COL-1)
		if (' ' == sudoku[row][col]) // 随机生成的位置为空格
		{
			sudoku[row][col] = flag_computer; // 存入电脑的标记符
			break; // 跳出循环
		}
		else // 随机生成的位置非空格
			continue; // 继续循环
	}
}

char check_sudoku(char sudoku[ROW][COL])
{ // 检查棋盘是否完成的函数
	int i, j; // 定义行列下标
	char flag_self = '*', flag_computer = '#'; // 定义标记符
	//int count_self = 0, count_computer = 0;
	int count_null = 0; // 计数器
	for (i = 0; i < ROW; ++i)
	{ // 检查行
		/*for (j = 0; j < COL; ++j)
		{
			if (sudoku[i][j] == flag_self) // 统计标记符的个数
				++count_self;
			else if (sudoku[i][j] == flag_computer)
				++count_computer;
			else
				++count_null;
		}
		if (CONTINUOUS == count_self) // 对每一行进行检查
			// 如果有3个标记符为自己的标记符，则棋盘完成
			return '1'; // 返回 '1' 表示完成且自己获胜
		else if (CONTINUOUS == count_computer) // 对每一行进行检查
			// 如果有3个标记符为电脑的标记符，则棋盘完成
			return '2'; // 返回 '2' 表示完成且电脑获胜
		else // 没有连起 CONTINUOUS 个相同标记符的情况
		{
			count_self = 0; // 重置自己的计数器
			count_computer = 0; // 重置电脑的计数器
		}*/

		for (j = 0; j < COL; ++j)
		{
			if (' ' == sudoku[i][j])
				++count_null;
			while (j <= COL - CONTINUOUS)
			{
				int k, count = 1;
				for (k = 1; k < CONTINUOUS; ++k)
				{
					if (sudoku[i][j] != ' ' &&
						sudoku[i][j] == sudoku[i][j + k])
						++count;
				}
				if (count == CONTINUOUS)
				{ // 连起 CONTINUOUS 个相同标记符的情况
					if (sudoku[i][j] == flag_self) // 自己的标记符
						return '1'; // 返回 '1' 表示完成且自己获胜
					else if (sudoku[i][j] == flag_computer)// 电脑的标记符
						return '2'; // 返回 '2' 表示完成且电脑获胜
					//else // 蜜汁情况
					//	break; // 退出循环
				}
				else // 没有连起 CONTINUOUS 个相同标记符的情况
					break; // 退出循环
			}
		}
	}

	for (j = 0; j < COL; ++j)
	{ // 检查列
		/*for (i = 0; i < ROW; ++i)
		{
			if (sudoku[i][j] == flag_self) // 统计标记符的个数
				++count_self;
			else if (sudoku[i][j] == flag_computer)
				++count_computer;
			else
				++count_null;
		}
		if (CONTINUOUS == count_self) // 对每一列进行检查
			// 如果有3个标记符为自己的标记符，则棋盘完成
			return '1'; // 返回 '1' 表示完成且自己获胜
		else if (CONTINUOUS == count_computer) // 对每一列进行检查
			// 如果有3个标记符为电脑的标记符，则棋盘完成
			return '2'; // 返回 '2' 表示完成且电脑获胜
		else // 没有连起 3 个相同标记符的情况
		{
			count_self = 0; // 重置计数器
			count_computer = 0; // 重置计数器
		}*/

		for (i = 0; i < ROW; ++i)
		{
			while (i <= ROW - CONTINUOUS)
			{
				int k, count = 1;
				for (k = 1; k < CONTINUOUS; ++k)
				{
					if (sudoku[i][j] != ' ' &&
						sudoku[i][j] == sudoku[i + k][j])
						++count;
				}
				if (count == CONTINUOUS)
				{ // 连起 CONTINUOUS 个相同标记符的情况
					if (sudoku[i][j] == flag_self) // 自己的标记符
						return '1'; // 返回 '1' 表示完成且自己获胜
					else if (sudoku[i][j] == flag_computer)// 电脑的标记符
						return '2'; // 返回 '2' 表示完成且电脑获胜
					//else // 蜜汁情况
					//	break; // 退出循环
				}
				else // 没有连起 CONTINUOUS 个相同标记符的情况
					break; // 退出循环
			}
		}
	}

	for (i = 0; i < ROW; ++i)
	{ // 检查斜线连接（斜线连续的 CONTINUOUS_TILT 个标记符就可结束游戏）
		/*if (0 == i && (sudoku[i][i] == sudoku[i + 1][i + 1] &&
			sudoku[i][i] == sudoku[i + 2][i + 2])) // 斜线统计标记符
		{
			if (sudoku[i][i] == flag_self) // 标记符是自己的标记符
				return '1'; // 返回 '1' 表示完成且自己获胜
			else if (sudoku[i][i] == flag_computer)// 标记符是电脑的标记符
				return '2'; // 返回 '2' 表示完成且电脑获胜
		}
		else if (2 == i && (sudoku[i - 2][i] == sudoku[i - 1][i - 1] &&
			sudoku[i - 2][i] == sudoku[i][i - 2]))
		{
			if (sudoku[i - 2][i] == flag_self) // 自己的标记符
				return '1'; // 返回 '1' 表示完成且自己获胜
			else if (sudoku[i - 2][i] == flag_computer) // 电脑的标记符
				return '2'; // 返回 '2' 表示完成且电脑获胜
		}
		else // 没有连起 CONTINUOUS 个相同标记符的情况
			continue; // 继续循环*/

		for (j = 0; j < COL; ++j)
		{ // 注意 i 和 j 是下标位置
			while (i <= ROW - CONTINUOUS_TILT &&
				j <= COL - CONTINUOUS_TILT)
			{
				int k, count = 1;
				for (k = 1; k <= CONTINUOUS_TILT; ++k)
				{
					if (sudoku[i][j] != ' ' &&
						sudoku[i][j] == sudoku[i + k][j + k])
						++count;
				}
				if (count == CONTINUOUS_TILT)
				{ // 斜线统计标记符
					if (sudoku[i][j] == flag_self) // 自己的标记符
						return '1'; // 返回 '1' 表示完成且自己获胜
					else if (sudoku[i][j] == flag_computer) // 电脑标记符
						return '2'; // 返回 '2' 表示完成且电脑获胜
					//else // 蜜汁情况
					//	break; // 退出循环
				}
				else // 没有连起 CONTINUOUS 个相同标记符的情况
					break; // 退出循环
			}
			while (i >= CONTINUOUS_TILT - 1 &&
				j <= COL - CONTINUOUS_TILT)
			{
				int k, count = 1;
				for (k = 1; k < CONTINUOUS_TILT; ++k)
				{
					if (sudoku[i][j] != ' ' &&
						sudoku[i][j] == sudoku[i - k][j + k])
						++count;
				}
				if (count == CONTINUOUS_TILT)
				{
					if (sudoku[i][j] == flag_self) // 自己的标记符
						return '1'; // 返回 '1' 表示完成且自己获胜
					else if (sudoku[i][j] == flag_computer) // 电脑标记符
						return '2'; // 返回 '2' 表示完成且电脑获胜
					//else // 蜜汁情况
					//	break; // 退出循环
				}
				else // 没有连起 CONTINUOUS 个相同标记符的情况
					break; // 退出循环
			}
		}
	}

	if (0 == count_null) // 检查没有空格
		return '0'; // 返回 '0' 表示棋盘完成且平局
	else // 棋盘没有完成
		return '3'; // 返回 '3' 表示没有完成，从未使用，只是为了让函数有返回值
}

void sudoku_game()
{ // 三子棋游戏的主函数
	char sudoku[ROW][COL] = { 0 }; // 定义一个 ROW x COL 的数组
	init_sudoku(sudoku); // 调用初始化棋盘的函数
	print_sudoku(sudoku); // 打印棋盘
	int row, col;
	//char flag_self = '*', flag_computer = '#';
	srand((unsigned int)time(NULL)); // 随机数种子

	do
	{
		player_move(sudoku); // 玩家下棋
		print_sudoku(sudoku); // 打印棋盘
		if ('1' == check_sudoku(sudoku)) // 自己获胜
		{
			printf("恭喜你，你赢了！\n");
			break;
		}
		else if ('0' == check_sudoku(sudoku)) // 平局
		{
			printf("平局！\n");
			break;
		}
		Sleep(100); // 延时0.1秒
		computer_move(sudoku); // 电脑下棋
		print_sudoku(sudoku); // 打印棋盘
		if ('2' == check_sudoku(sudoku)) // 电脑获胜
		{
			printf("电脑赢了！\n");
			break;
		}
		else if ('0' == check_sudoku(sudoku)) // 平局
		{
			printf("平局！\n");
			break;
		}
	} while (1);
}

void sudoku_start()
{ // 三子棋游戏的入口函数
	int choice;
	do
	{
		//system("cls"); // 清屏
		//select_num(); // 未完成的自定义模式
		sudoku_menu();
		printf("请输入你的选择：");
		int scanf_ret = scanf("%d", &choice);
		if (1 != scanf_ret)
		{
			printf("输入错误，请重新输入！\n");
			clean_cache(); // 清理缓存区
			continue;
		}
		switch (choice)
		{
		case 1:
			printf("开始游戏\n");
			sudoku_game();
			break;
		case 0:
			printf("已退出游戏\n");
			break;
		default:
			printf("输入错误，请重新输入！\n");
			break;
		}
		if (0 == choice)
			break;
	} while (choice);
}


//int main()
//{
//	sudoku_start();
//	return 0;
//}